# -*- coding:utf-8 -*- 
# Author: json_steve

from . import api
from iHome.models import Area, House, Facility, HouseImage, Order
from flask import current_app, jsonify, request, g, session,logging
from iHome.utils.response_code import RET
from iHome import redis_store,db
from iHome.constants import AREA_INFO_REDIS_EXPIRES,QINIU_DOMIN_PREFIX, \
    HOUSE_DETAIL_REDIS_EXPIRE_SECOND,HOME_PAGE_MAX_HOUSES,\
    HOME_PAGE_DATA_REDIS_EXPIRES, HOUSE_LIST_PAGE_CAPACITY,HOUSE_LIST_REDIS_EXPIRES
from iHome.utils.common import login_required
from iHome.utils.iamge_storage import storage_image
import datetime


# 展示所有房屋信息
@api.route('/houses')
def get_house_list():
    """
    1. 先加载所有的房屋信息
    ２.增加按区域查询
    ３．增加日期查询　先查找不符合的（被预定，时间有冲突的），然后取反
    4.ｒｅｄｉｓ缓存
    :return:
    """
    # 去查询所有数据
    args = request.args

    # 获得前端需要的请求页数
    p = args.get('p',1)

    # 获得排序方式
    sk = args.get('sk', 'new')

    # 增加按地址区域查询
    aid = args.get('aid', '')

    # 获取查询时间的参数
    start_date_str = args.get('sd', '')
    end_date_str = args.get('ed', '')
    # 时间参数判断
    start_date = None  # 防止后面的ｉｆ出错
    end_date = None
    try:
        if start_date_str:
            start_date = datetime.datetime.strptime(start_date_str, "%Y-%m-%d")
        if end_date_str:
            end_date = datetime.datetime.strptime(end_date_str, "%Y-%m-%d")
        if start_date_str and end_date_str:
            assert end_date > start_date, Exception("结束时间必须大于开始时间")
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg='参数错误')

    try:
        p = int(p)
    except Exception as e:
        current_app.logger.error()
        return jsonify(errno=RET.PARAMERR, errmsg='参数错误')

    # 先从缓冲中获取数据
    try:
        redis_key = "house_list_%s_%s_%s_%s" % (start_date_str, end_date_str, aid, sk)
        response = redis_store.hget(redis_key, p)
        # print 'redis'
        if response:
            return jsonify(errno=RET.OK, errmsg='ok', data=eval(response))
    except Exception as e:
        current_app.logger.error(e)

    try:
        # houses = House.query.all()
        houses_query = House.query
        # print 'mysql'
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询数据失败")

    # 增加地址过滤的查询条件
    filters = []
    if aid:
        filters.append(House.area_id == aid)

    # 查找是见冲突的订单
    confilect_orders = None
    if start_date and end_date:
        confilect_orders = Order.query.filter(Order.begin_date < end_date, Order.end_date > start_date).all()
    elif start_date:  # 有问题先放到这里
        confilect_orders = Order.query.filter(Order.end_date > start_date).all()
    elif end_date:  # 有问题先放到这里
        confilect_orders = Order.query.filter(Order.begin_date < end_date).all()
    # 冲突存在增加过滤条件　否则不用增加
    if confilect_orders:
        # 冲突的房屋ｉｄ
        confilect_house_ids =[order.house_id for order in confilect_orders]
        # 添加到过滤条件里
        filters.append(House.id.notin_(confilect_house_ids))
    # 添加排序逻辑
    if sk == "booking":
        houses_query = houses_query.filter(*filters).order_by(House.order_count.desc())
    elif sk == "price-inc":
        houses_query = houses_query.filter(*filters).order_by(House.price)
    elif sk == "price-des":
        houses_query = houses_query.filter(*filters).order_by(House.price.desc())
    else:
        houses_query = houses_query.filter(*filters).order_by(House.create_time.desc())
    # 进行分页 > 参1：查询第几页，参数2：每一页多少条，参数3：是否抛出错误
    paginate = houses_query.paginate(p, HOUSE_LIST_PAGE_CAPACITY, False)
    # 取到总页数
    total_page = paginate.pages
    # 取到当前页的数据
    houses = paginate.items
    # 将数据转成字典列表进行返回
    houses_dict = []
    for house in houses:
        houses_dict.append(house.to_basic_dict())
    # return jsonify(errno=RET.OK, errmsg="OK", data={"houses": houses_dict, "total_page": total_page})
    # 缓存数据
    response = {"houses": houses_dict, "total_page": total_page}
    try:
        # 键　页做属性　ｒｅｓｐｏｎｓｅ做值
        redis_key = "house_list_%s_%s_%s_%s" % (start_date_str, end_date_str, aid, sk)
        # 生成管道对象
        pipeline = redis_store.pipeline()
        # 开启事物
        pipeline.multi()
        # 保存数据
        pipeline.hset(redis_key,p,response)
        # 设置过期时间
        pipeline.expire(redis_key,HOUSE_LIST_REDIS_EXPIRES)
        # 执行管道
        pipeline.execute()
    except Exception as e:
        current_app.logger.error(e)
    return jsonify(errno=RET.OK, errmsg='ok', data=response)


# 首页推荐房屋信息
@api.route("/houses/index")
def get_house_index():
    """
    1. 查询数据库 > order_by，limit
    2. 返回

    :return: 首页订单量最高的5条数据
    """
    # 先从缓存中去加载数据
    try:
        houses_dict = redis_store.get("home_house")
        if houses_dict:
            return jsonify(errno=RET.OK, errmsg="OK", data={"houses": eval(houses_dict)})
    except Exception as e:
        current_app.logger.error(e)

    try:
        houses = House.query.order_by(House.order_count.desc()).limit(HOME_PAGE_MAX_HOUSES)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询数据失败")

    # 将对象列表转成字典列表
    houses_dict = []
    for house in houses:
        houses_dict.append(house.to_basic_dict())

    # 将数据进行缓存
    try:
        redis_store.set("home_house", houses_dict, HOME_PAGE_DATA_REDIS_EXPIRES)
    except Exception as e:
        current_app.logger.error(e)

    return jsonify(errno=RET.OK, errmsg="OK", data={"houses": houses_dict})


# 首页右上角返回用户ｉｄ和名，ｂｏｏｋｉｎｇ
@api.route('/session')
def check_login():
    """
    检测用户是否登录，如果登录，则返回用户的名和用户id
    :return:
    """
    # 从 session 中取出用户的信息
    user_id = session.get("user_id")
    name = session.get("name")
    # 直接返回
    return jsonify(errno=RET.OK, errmsg="OK", data={"user_id": user_id, "name": name})


# 房屋详细信息
@api.route("/houses/<int:house_id>")
def get_house_detail(house_id):
    """
    1. 通过房屋的id查询出指定的房屋
    2. 将房屋的相关数据进行返回(房屋信息，当前登录用户的id)
    3. 考虑是否缓存的问题
    :param house_id:
    :return:
    """
    # 先尝试从redis中去取
    # 获取到当前登录用户的id，如果没有登录，那么就返回-1
    user_id = session.get("user_id", -1)
    try:
        house_dict = redis_store.get(("house_detail_%d" % house_id))
        # 如果取到有数据，那么直接返回
        if house_dict:
            return jsonify(errno=RET.OK, errmsg="OK", data={"user_id": user_id, "house": eval(house_dict)})
    except Exception as e:
        current_app.logger.error(e)

    # 从 Mysql 数据库中查询数据
    try:
        house = House.query.get(house_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="数据查询错误")

    if not house:
        return jsonify(errno=RET.NODATA, errmsg="房屋不存在")

    house_dict = house.to_full_dict()

    # 缓存当前房屋数据
    try:
        redis_store.set(("house_detail_%d" % house_id), house_dict, HOUSE_DETAIL_REDIS_EXPIRE_SECOND)
    except Exception as e:
        current_app.logger.error(e)

    return jsonify(errno=RET.OK, errmsg="OK", data={"user_id": user_id, "house": house_dict})


# 添加新房屋
@api.route('/house', methods=['POST'])
@login_required
def save_new_house():
    """
    1.获取参数,判断参数
    2.house模型对象
    3.保存数据到数据库
    :return:
    """
    user_id = g.user_id
    # 获取参数
    json_dict = request.json
    title = json_dict.get('title')
    price = json_dict.get('price')
    address = json_dict.get('address')
    area_id = json_dict.get('area_id')
    room_count = json_dict.get('room_count')
    acreage = json_dict.get('acreage')
    unit = json_dict.get('unit')
    capacity = json_dict.get('capacity')
    beds = json_dict.get('beds')
    deposit = json_dict.get('deposit')
    min_days = json_dict.get('min_days')
    max_days = json_dict.get('max_days')
    # 1.1 判断是否都有值
    if not all(
            [title, price, address, area_id, room_count, acreage, unit, capacity, beds, deposit, min_days, max_days]):
        return jsonify(errno=RET.PARAMERR, errmsg="参数有误")
    # 1.2 校验参数格式是否正确
    try:
        price = int(float(price) * 100)  # 以整数形式存储,存储单位是分，但是传过来的是元
        deposit = int(float(deposit) * 100)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg="参数有误")

    house = House()  # 创建模型对象
    house.user_id = user_id  #　保存用户ｉｄ
    house.area_id = area_id
    house.title = title
    house.price = price
    house.address = address
    house.room_count = room_count
    house.acreage = acreage
    house.unit = unit
    house.capacity = capacity
    house.beds = beds
    house.deposit = deposit
    house.min_days = min_days
    house.max_days = max_days
    # 获取到当前房屋的设施列表数组
    facilities = json_dict.get("facility")
    if facilities:
        house.facilities = Facility.query.filter(Facility.id.in_(facilities)).all()

    # 存入数据库
    try:
        db.session.add(house)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg='存储数据失败')

    return jsonify(errno=RET.OK, errmsg='ok', data={'house_id': house.id})


# 添加房屋图片
@api.route("/houses/<int:house_id>/images", methods=['POST'])
@login_required
def upload_house_image(house_id):
    """
    1. 取到上传的图片
    2. 进行七牛云上传
    3. 将上传返回的图片地址存储
    4. 进行返回
    :return:
    """

    # 1. 取到上传的图片
    try:
        house_image_file = request.files.get("house_image").read()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg="参数不全")

    # 2. 查询房屋是否存在
    try:
        house = House.query.get(house_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询房屋失败")

    if not house:
        return jsonify(errno=RET.NODATA, errmsg="房屋不存在")

    # 3. 上传到七牛云
    try:
        url = storage_image(house_image_file)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.THIRDERR, errmsg="上传图片失败")

    # 4. 初始化房屋的图片模型
    house_image = HouseImage()
    # 设置相关数据
    house_image.house_id = house.id
    house_image.url = url

    # 判断是否有首页图片
    if not house.index_image_url:
        # 保存图片地址
        house.index_image_url = url

    # 更新到数据库
    try:
        db.session.add(house_image)
        db.session.commit()
    except Exception as e:
        db.session.rollback()
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="保存数据失败")

    return jsonify(errno=RET.OK, errmsg="OK", data={"url": QINIU_DOMIN_PREFIX + url})


# 查询城区
@api.route('/areas')
def get_areas():
    """
    1.获取城市信息
    2.返回前端
    :return:
    """
    # 缓存到redis中，先从redis中查找
    try:
        areas_dict = redis_store.get('areas')
    except Exception as e:
        current_app.logger.error(e)
        # 不返回因为向下执行取数据库中查找，找到了不用去数据库里找
        areas_dict = None  # 防止后面if 出错
    if areas_dict:
        return jsonify(errno=RET.OK, errmsg="ok", data=eval(areas_dict))  # 存到redis的数据【】变成'[]',eval
    # 从数据库中查询
    try:
        areas = Area.query.all()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errnsg='查询数据错误')
    # 不写也行
    if not areas:
        return jsonify(errno=RET.DBERR,errmsg='数据尚未添加')

    # 不能直接返回对象
    areas_dict = []
    for area in areas:
        areas_dict.append(area.to_dict())

    # 缓存areas_dict
    try:
        redis_store.set("areas", areas_dict, AREA_INFO_REDIS_EXPIRES)
    except Exception as e:
        current_app.logger.error(e)
        # 不用返回

    return jsonify(errno=RET.OK, errmsg='ok', data=areas_dict)


# 房源信息
@api.route('/myhouses',methods=['GET'])
@login_required
def get_myhouses_information():
    """
    获得房东的房源信息
    １，获取房东
    2,获取房东的房子
    ３，组织参数返回
    :return:
    """
    user_id = g.user_id
    try:
        # 先查找房东下的所有房子
        houses = House.query.filter(House.user_id == user_id).all()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='数据查询错误')
    # 组织参数
    houses = [house.to_basic_dict() for house in houses]

    return jsonify(errno=RET.OK, errmsg='ok', data={'houses': houses})


